package com.evendai.sipdemo.sip.audio

import android.annotation.SuppressLint
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.PixelFormat
import android.os.Build
import android.os.IBinder
import android.os.Message
import android.view.*
import com.evendai.loglibrary.Timber
import com.evendai.sipdemo.App
import com.evendai.sipdemo.Constants
import com.evendai.sipdemo.databinding.IncomingViewBinding
import com.evendai.sipdemo.sip.listener.FloatViewOnTouchListener
import com.evendai.sipdemo.util.SipUtil
import org.doubango.Whats
import org.doubango.ngn.events.NgnInviteEventArgs
import org.doubango.ngn.events.NgnInviteEventTypes
import org.doubango.ngn.media.NgnMediaType
import org.doubango.ngn.sip.NgnAVSession
import org.doubango.ngn.utils.NgnUriUtils
import org.doubango.tinyWRAP.SipUri
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe

/** 用于接收来电的服务 */
class IncomingService : Service() {

    private var incomingSession : NgnAVSession? = null
    private var binding: IncomingViewBinding? = null

    private val broadcaster = object: BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            if (NgnInviteEventArgs.ACTION_INVITE_EVENT == intent.action) {
                this@IncomingService.onReceive(intent)
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        registerReceiver(broadcaster, IntentFilter(NgnInviteEventArgs.ACTION_INVITE_EVENT))
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this)
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return START_NOT_STICKY
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(broadcaster)
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this)
        }
    }

    private fun onReceive(intent: Intent) {
        val args = intent.getParcelableExtra<NgnInviteEventArgs>(NgnInviteEventArgs.EXTRA_EMBEDDED) ?: return

        Timber.i("sessionId = ${args.sessionId}，eventType = ${args.eventType}，mediaType = ${args.mediaType}")
        // 当有电话呼入时会收到如下eventType事件：
        // eventType = INCOMING

        // 没接电话时，对方主动挂断，会依次收到如下eventType事件：
        // eventType = SIP_RESPONSE
        // eventType = TERMINATED

        // 没接电话时，我们主动挂断，收到如下eventType事件：
        // eventType = TERMINATED

        // 接通电话时会依次收到如下eventType事件：
        // eventType = CONNECTED
        // eventType = SIP_RESPONSE

        // 接通电话后，对方主动挂断时会依次收到如下eventType事件：
        // eventType = TERMINATED

        // 接通电话后，我们主动挂断时会依次收到如下eventType事件：
        // eventType = TERMWAIT
        // eventType = TERMINATED

        if (!NgnMediaType.isAudioVideoType(args.mediaType)) {
            Timber.fe(Exception("不是音视频类型，不处理, mediaType = ${args.mediaType}"))
            // 其它类型有：NgnMediaType.isFileTransfer(mediaType)、NgnMediaType.isChat(mediaType)
            return
        }

        when (args.eventType) {
            NgnInviteEventTypes.INCOMING -> {
                if (incomingSession?.isActive == true) {
                    // TODO 已经有一个电话呼入了。另外如果有一个电话正在呼出时也不应该处理，看怎样可以通过NgnApi拿到所有的会话对象
                    Timber.fw("正在通着电话了，又有一个电话打进来")
                    return
                }

                NgnAVSession.getSession(args.sessionId)?.let {
                    if (SipUtil.isVideoCall(it)) {
                        Timber.i("来了一个视频电话")
                        return@let
                    }

                    incomingSession = it
                    val remotePartyUri = it.remotePartyUri
                    val incomingNumber = SipUri(remotePartyUri).userName
                    val userName = NgnUriUtils.getUserName(remotePartyUri)
                    val displayName = NgnUriUtils.getDisplayName(remotePartyUri)
                    val validPhoneNumber = NgnUriUtils.getValidPhoneNumber(remotePartyUri)
                    Timber.i("userName = $userName，displayName = $displayName，validPhoneNumber = $validPhoneNumber")
                    Timber.i("接到来电：incomingNumber = $incomingNumber，remotePartyUri = ${remotePartyUri}，remotePartyDisplayName = ${it.remotePartyDisplayName}")
                    showIncomingView(it)
                }
            }
            NgnInviteEventTypes.TERMINATED -> {
                if (args.sessionId == incomingSession?.id) {
                    closeIncomingView()
                    incomingSession = null
                }
            }
            else -> { }
        }
    }

    /** 显示呼入电话悬浮窗 */
    @SuppressLint("ClickableViewAccessibility")
    @Suppress("DEPRECATION")
    fun showIncomingView(incomingSession: NgnAVSession) {
        closeIncomingView()

        val binding = IncomingViewBinding.inflate(LayoutInflater.from(App.getContext()), null, false).also { binding = it }
        binding.btnAcceptCall.setOnClickListener { acceptCall(); it.visibility = View.GONE }
        binding.btnHangupCall.setOnClickListener { hangupCall(); closeIncomingView() }
        binding.tvCallState.text = incomingSession.remotePartyDisplayName

        val floatViewType = when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 -> WindowManager.LayoutParams.TYPE_PHONE
            else -> WindowManager.LayoutParams.TYPE_TOAST
        }

        val windowManager = App.getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val params = WindowManager.LayoutParams().apply {
            type = floatViewType
            flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE // 不设置这个flag的话，屏幕上任何内容都没法接收触摸事件了
            width = WindowManager.LayoutParams.WRAP_CONTENT
            height = WindowManager.LayoutParams.WRAP_CONTENT
            gravity = (Gravity.END or Gravity.BOTTOM)
            format = PixelFormat.TRANSLUCENT
        }
        binding.root.setOnTouchListener(FloatViewOnTouchListener(params, windowManager))
        windowManager.addView(binding.root, params)
    }

    private fun acceptCall() {
        incomingSession?.acceptCall()
        incomingSession?.setSpeakerphoneOn(Constants.sSpeakerphoneOn)
    }

    private fun hangupCall() {
        Timber.i("挂电话")
        incomingSession?.hangUpCall()
        incomingSession = null
    }

    private fun closeIncomingView() {
        val incomingView = binding?.root
        if (incomingView != null) {
            (App.getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager).removeView(incomingView)
            binding = null
        }
    }

    @Suppress("unused")
    @Subscribe
    fun setSpeakerphoneOn(message: Message) {
        if (message.what == Whats.SET_SPEAKERPHONE_ON) {
            val speakerOn = message.obj as Boolean
            incomingSession?.setSpeakerphoneOn(speakerOn)
            Timber.i("收到扬声器开关消息，speakerOn = $speakerOn")
        }
    }

    override fun onBind(intent: Intent): IBinder? = null
}